<?php
/**
 * urls data structure.
 * parses url string, allows to get/set any part :
 * <ul>
 * <li>scheme</li>
 * <li>host</li>
 * <li>base path</li>
 * <li>relative path</li>
 * <li>query vars</li>
 * <li>fragment</li>
 * </ul>
 * This file belongs to a webappkit package (kit)
 * @link http://webappkit.net
 * @package databeans
 * @subpackage http
 * @author J.Ducastel <nospam0@ducastel.name>
 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
 */
class UrlBean extends DataBean {
/*------------------------------------------------------------------------------
                                                                     constructor
------------------------------------------------------------------------------*/
	/**
	* constructor alias
	* @see urlbean::__construct()
	* @access public
	*/
	function UrlBean($url=NULL,$base=NULL) {
		$this->__construct($url,$base);
	}/**/
	/**
	* "real" constructor.
	* @access public
	* @param string $url
	* @param string $base base url for relative urls, as in <base href>
	*/
	function __construct($url=NULL,$base=NULL) {
		$this->membersLock();
		$parts=$this->parseString($url); //print_r($parts);
		if ($parts) {
			$this->loadData($parts);
		}
		if ($base)
			$this->setbasepath($base,true);
		// echo '<pre>'; print_r($this);
	}

	function __toString() {
		return $this->getAbsolute();
	}
/*------------------------------------------------------------------------------
                                                                  public methods
------------------------------------------------------------------------------*/
	/**
	* parse an url string.
	* @access public
	* @param string $string url as a string
	* @static
	* @return array parsed string
	*/
	function parseString($string=NULL) {

		$data=parse_url($string); //print_r($data);
		$data['scheme']=isset($data['scheme'])?$data['scheme']:null;
		//$data['host']=isset($data['host'])?$data['host']:null;
		// parsing query
		$getVars=isset($data['query'])?explode('&',$data['query']):array();
		$data['vars']=array();
		foreach ($getVars as $var) {
			if (!$var) continue;
			$var=explode('=',$var);
			$data['vars'][$var[0]]=$var[1];
		}
		// parsing fragment
		if (ereg('#(.+)$',$string,$search))
			$data['fragment']=$search[1];
		else $data['fragment']=null;
		// echo wakaffvar($data);
		return $data;
	}/**/

	/**
	* returns the relative url (without base).
	* @access public
	* @return string
	*/
	function getRelative() {
		$path=$this->getPath();
		$query=$this->getquery();
		$fragment=$this->getfragment();
		return $path
		.($query?'?'.$query:'')
		.($fragment?'#'.$fragment:'');
	}/**/

	/**
	* returns the full absolute url
	* @access public
	* @return string
	*/
	function getAbsolute() {
		$scheme=$this->getscheme();
		$host=$this->getHost();
		$basepath=$this->getBasePath();
		$path=$this->getPath();
		$query=$this->getquery();
		$fragment=$this->getfragment();
		return $scheme.'://'
		.$host.'/'
		.($basepath?$basepath.'/':'')
		.$path
		.($query?'?'.$query:'')
		.($fragment?'#'.$fragment:'');
	}/**/

	/**
	* returns the query part (without ?)
	* do not converts & to &amp;
	* @access public
	* @return string
	*/
	function getQuery() {
		$query='';
		foreach($this->vars as $key => $value) {
			$query.="$key=$value&";
		}
		// wiping last unnecessary &amp;
		$query=substr($query,0,-1);
		return $query;
	}/**/

	/**
	* return current $scheme value
	* @access public
	* @return string current $scheme
	*/
	function getScheme() {
		return $this->getMember('scheme');
	}/**/

	/**
	* set $scheme value
	* @access public
	* @return string current $scheme
	*/
	function setScheme($scheme=null) {
		return $this->setMember('scheme',$scheme);
	}/**/

	/**
	* return current $host value
	* @access public
	* @return string current $host
	*/
	function gethost() {
		return $this->getMember('host');
	}/**/

	/**
	* set $host value
	* @access public
	* @return string current $host
	*/
	function sethost($host=null) {
		return $this->setMember('host',$host);
	}/**/

	/**
	* return current $path value
	* @access public
	* @return string current $path
	*/
	function getpath() {
		return $this->getMember('path');
	}/**/

	/**
	* sets $path value
	* @access public
	* @return string current $path
	*/
	function setpath($path) {
		return $this->setMember('path',$path);
	}

    /**
     * splits path part into segments separated by /
     * @access public
     * @return array
     */
    function splitPath() {
        return explode('/',$this->get('path'));
    }

	/**
	* return $index segment of uri.
	* i.e. part after $index number of slashes and before next slash
	* @access public
	* @param int $index
	* @return mixed string|null
	*/
	function getUriSegment($index) {
		if (!$path=$this->getMember('path'))
			return null;
		$segments=explode('/',$path);
		return isset($segments[$index])?$segments[$index]:null;
	}

	/**
	* return current $basepath value
	* @access public
	* @return bool
	*/
	function getBasePath() {
		return $this->getMember('basepath');
	}/**/

	/**
	* sets $basepath value
	* @param string $base base url
	* @access public
	* @return bool
	*/
	function setbasePath($basepath=null) {
		return $this->set('basepath',$basepath);
	}/**/

	/**
	* return $vars[$var] value
	* @access public
	* @param string $key var's key
	* @return mixed usually a string
	*/
	function getvar($key) {
		if (!isset($this->vars[$keys])) return null;
		return $this->vars[$key];
	}/**/

	/**
	* sets $vars[$var] value
	* @access public
	* @param $key string var's key
	* @param mixed $value var's new value
	* @return string current $scheme
	*/
	function setvar($key, $value) {
		$this->vars[$key]=$value;
		return true;
	}/**/

	/**
	* return current $vars as an associative array
	* @access public
	* @return array
	*/
	function getvars() {
		return $this->get('vars');
	}/**/

	/**
	* sets all vars form a n associative array
	* @access public
	* @param array $vars
	* @return bool
	*/
	function setvars($vars) {
		return $this->setMember('vars',$vars);
	}/**/

	/**
	* return current $fragment value
	* @access public
	* @return string current $scheme
	*/
	function getfragment() {
		return $this->get('fragment');
	}/**/
	/**
	* sets $fragment value
	* @access public
	* @return string current $scheme
	*/
	function setfragment($fragment) {
		return $this->setMember('fragment',$fragment);
	}/**/

/*------------------------------------------------------------------------------
                                                                      properties
------------------------------------------------------------------------------*/
	//var $_databean_members_lock=true;

	/**
	* @var type desc
	*/
	var $scheme='http';
	function _scheme_check($x) {
		return in_array($x,array('http','https','ftp'));
	}
	/**
	* @var type desc
	*/
	var $host;
	function _host_check($x) {
		return ereg('^[a-zA-Z0-9\.-]+$',$x);
	}
	/**
	* @var string base path, part ignored for relative path
	* (= physical path to index)
	*/
	var $basepath;
	function _basepath_check($x) {
		return ereg('^[a-zA-Z0-9_/\.-]+$',$x);
	}
	function _basepath_set($base) {
		$base=trim($base,'/');
		// checking
		if (!$this->_basepath_check($base))
			return false;
		// adjusting relative path
		// what is the full path ? base + relative
		$full=($this->basepath?$this->basepath.'/':'')
		.$this->path;
		//echo "<p>full = $full</p>";
		// checking that the new relative path is included in current path
		if (substr($full,0,strlen($base))!=$base) {
			return false;
		}
		$newpath=substr($full,strlen($base)+1);
		$this->path=$newpath;
		// echo "<p>newpath=$newpath</p>";
		$this->basepath=$base;
		return true;
	}
	/**
	* @var string relative path (not starting by /)
	*/
	var $path;
	function _path_check($x) {
		return ereg('^[a-zA-Z0-9_/\.-]*$',$x);
	}
	function _path_inputfilter($path) {
		$newpath=trim($path,'/'); //echo "$path >> $newpath";
		return $newpath;
	}/**/

	/**
	* @var array GET vars
	*/
	var $vars;
	function _vars_check($x) {
		return is_array($x);
	}
	//function _vars
	/**
	* @var type desc
	*/
	var $fragment;
	function _fragment_check($x) {
		return is_string($x) and ereg('^[a-zA-Z][a-zA-Z0-9_-]*$',$x);
	}
	function _fragment_inputfilter($fragment) {
		if (is_string($fragment))
			$fragment=str_replace('#','',$fragment);
		return $fragment;
	}

	/**
	* @var type desc
	*/
	//var //
}